﻿using HtmlAgilityPack;
using System;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;

namespace XCrawler.HtmlParser
{
    /// <summary>
    /// 【HTML】工作解析器
    /// </summary>
    public class HtmlWorkerParser : ICrawlerParser
    {
        /// <summary>
        /// 可解析的ContentType
        /// 默认: "text/html"
        /// </summary>
        public string[] ContentTypes { get; set; } = new string[] { "text/html" };

        /// <summary>
        /// 解析器处理函数
        /// </summary>
        /// <param name="crawler">爬虫</param>
        /// <param name="parserBag">爬虫返回信息包</param>
        /// <returns></returns>
        public virtual async Task DoWorkAsync(ICrawler crawler, ParserBag parserBag)
        {
            if (parserBag.StatusCode != HttpStatusCode.OK)
            {
                return;
            }

            if (!IsHtmlContent(parserBag.ContentType))
            {
                return;
            }

            //检测SourceText有没有
            if (parserBag.SourceText.IsNullOrWhiteSpace())
            {
                await new StringWorkerParser().DoWorkAsync(crawler, parserBag).ConfigureAwait(false);
            }

            if(!parserBag.SourceText.IsNullOrWhiteSpace())
            {
                var htmlDoc = new HtmlDocument
                {
                    OptionAddDebuggingAttributes = false,
                    OptionAutoCloseOnEnd = true,
                    OptionFixNestedTags = true,
                    OptionReadEncoding = true
                };

                htmlDoc.LoadHtml(parserBag.SourceText);
                parserBag["HtmlDocument"] = htmlDoc;

                var nodes = htmlDoc.DocumentNode.SelectNodes("//title");
                // Extract Title
                if (!nodes.IsNull())
                {
                    parserBag["HtmlTitle"] = string.Join(";", nodes.
                        Select(n => n.InnerText).
                        ToArray()).Trim();
                }

                // Extract Meta Data
                nodes = htmlDoc.DocumentNode.SelectNodes("//meta[@content and @name]");
                if (!nodes.IsNull())
                {
                    parserBag["HtmlMeta"] = (
                        from entry in nodes
                        let name = entry.Attributes["name"]
                        let content = entry.Attributes["content"]
                        where !name.IsNull() && !name.Value.IsNullOrEmpty() && !content.IsNull() && !content.Value.IsNullOrEmpty()
                        select name.Value + ": " + content.Value).ToArray();
                }
            }
        }

        /// <summary>
        /// 是否为HTML类型
        /// </summary>
        /// <param name="contentType"></param>
        /// <returns></returns>
        private bool IsHtmlContent(string contentType)
        {
            return this.ContentTypes.Where(x => contentType.StartsWith(x, StringComparison.OrdinalIgnoreCase)).Any();
        }
    }
}
